#include <stdio.h>
#include <intrins.h>
#include <string.h>

#define usb_printf(info)        while (bUsbInBusy);  printf_usb(info);

#include "stc8h.h"
#include "stc32_stc8_usb.h"
#include "uart.h"

//char *USER_DEVICEDESC = NULL;
//char *USER_PRODUCTDESC = NULL;
//char *USER_STCISPCMD = "@STCISP#";



void sys_init(void);


//#define MAIN_Fosc        22118400L     //定义主时钟
//#define MAIN_Fosc        12000000L     //定义主时钟
//#define MAIN_Fosc        11059200L     //定义主时钟
//#define MAIN_Fosc         5529600L     //定义主时钟
//#define MAIN_Fosc        24000000UL    //定义主时钟
//#define MAIN_Fosc        33177600UL    //定义主时钟, for uart2 use BR=115200
#define MAIN_Fosc        35000000UL    //定义主时钟

//========================================================================
// 函数: void delay_ms(unsigned int ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-3-9
// 备注: 
//========================================================================

u8 data delay_int;

void delay_ms(u8 ms)
{
    do{
        delay_int = MAIN_Fosc / 10000;
        while(--delay_int);
    }while(--ms);
}

void delay_us(u8 ns)
{
    while(ns)
    {
      delay_int = 10;
      while (delay_int) --delay_int;
      --ns;
    }
}
void delay_50(void)
{
    delay_int = 5;
    while (--delay_int);
}

void delay_100(void)
{
    delay_int = 9;
    while (--delay_int);
}

void delay_500(void)
{
    delay_int = 50;
    while (--delay_int);
}



// 数据
// P6 D0-D7
// P7 D8-D15

// 地址
// P0 A0-A7
// P2 A8-A15
// P4 A16-A23
// P10 A24
// P11 A25

// BYTE P13

// OE P14
// CE P15
// WE P16

// MD共计使用 16+21+4=41脚

// MD A1-A21 对应芯片使用 A0-A20 4M





//缓存
#define BUFF_LEN 4096

#define BYTE P13
#define OE P14
#define CE P15
#define WE P16
#define RESET P17
#define READY P37


u8 data cmd;
u8 cmdBuffer[64];


u16 data i16;
u16 data j16;
u16 data x,y;

// 高位
u8  data wordL;
// 低位
u8  data wordH;

u8  data data8;
u16 data data16;
u32 data data32;
u16 data temp16;
//最大256
u32 data buff = 128;
u16 data buff16;
u16 data count16;

// 查空统计
u16 data checkFF_count;

// CFI缓存
u16 data cfi_buff8 = 0;
u16 data cfi_buff16 = 0;
u16 data write16;
// CFI 写入长度
u16 data write_word_index;


//0xF1 设置地址 4字节
u32 data address = 0;
u32 data address16 = 0;
//0xF2 设置缓存 4字节

//0xF3 设置写入字节长度 1、64、128、256、512 2字节
u32 data writeBuff = 1;
//0xF4 设置读写数据显示顺序，默认1显示 高位+地位
u8 data md_mode = 1;

// 64字节输出使用
//u8 data out64[64];

// 写入用缓存的位置
u16 data buffer_index = 0;
// 临时缓存空间 写入功能缓存待写数据
u8 xdata pageBuffer[BUFF_LEN];//最大 4096

const u8 version[] = "20250410\r\n";



void sys_init()
{
    P_SW2 |= 0x80;//扩展寄存器(XFR)访问使能
    
    P0M0 = 0xff;   P0M1 = 0x00;// A0-7
    //P1M0 = 0xfc;   P1M1 = 0x00;// p1.0 p1.1 for uart2 use
    P1M0 = 0xff;   P1M1 = 0x00;// A24-A25
    P2M0 = 0xff;   P2M1 = 0x00;// A8-15
    P3M0 = 0x00;   P3M1 = 0x00;
    P4M0 = 0xff;   P4M1 = 0x00;// A16-23
    P5M0 = 0x00;   P5M1 = 0x00;
    P6M0 = 0xff;   P6M1 = 0x00;// D0-D7
    P7M0 = 0xff;   P7M1 = 0x00;// D8-D15

    P3M0 &= ~0x03; P3M1 |= 0x03;    
    
    // P37 输入
    P3M0 &= ~0x80; P3M1 |= 0x80; 

    
    // 地址线0
    P0 = 0;
    P2 = 0;
    P4 = 0;
    
    // 地址线高位2个地址
    P10 = 0;
    P11 = 0;
    
    // 16位模式
    BYTE = 1;
    
    // 
    OE = 1;
    CE = 1;
    WE = 1;
    RESET = 1;
    

    //IRC48MCR = 0x80;//使能内部48M高速IRC
    //while (!(IRC48MCR & 0x01));//等待时钟稳定
    
    //USBCLK = 0x00;
    //USBCON = 0x90;

    //Uart2_Init();
}




// 串口收发 参考 https://www.stcaimcu.com/forum.php?mod=viewthread&tid=2392

u8 char1[1];    // 用于输出
void usb_sendchar(u8 c)
{
  char1[0]=c;
  USB_SendData(char1,1);
  usb_OUT_done();
}    

void usb_send_length(u8 cs[], u8 length)
{
    while (bUsbInBusy);
    USB_SendData(cs,length);
}


void usb_send(u8 cs[],u16 length)
{
#define SEND_PKG_SIZE 32
    u16 tmp = 0;
    
    if (length <= SEND_PKG_SIZE){
        usb_send_length(&cs[tmp], length);
    }else{
        while (tmp < length) {
            usb_send_length(&cs[tmp], SEND_PKG_SIZE);
            tmp += SEND_PKG_SIZE;
        }
    }
}


//读取写入数据缓存
void readBuffer()
{
    u16 data idx = 0;
    u16 data i;

    while(idx < buff) {
        if (bUsbOutReady) {
            if (OutNumber > 0) {
                for (i = 0; i < OutNumber; i++) {
                    pageBuffer[idx++] = UsbOutBuffer[i];
                }
            }
            usb_OUT_done();
        }
    }

    //usb_printf("ok\r\n");
    //printf_usb("ok\r\n");
}

////读取写入数据缓存
//void readBuffer64()
//{
//    u8 i;
//    while(1){
//      if (bUsbOutReady){
//        if(OutNumber>0){
//          for(i=0;i<OutNumber;i++){
//            pageBuffer[i]=UsbOutBuffer[i];
//          }
//          usb_OUT_done();
//          return;
//        }
//      }
//    }
//}


//void readBuffer128()
//{
//    u8 i;
//    while(1){
//      if (bUsbOutReady){
//        if(OutNumber>0){
//          for(i=0;i<OutNumber;i++){
//            pageBuffer[i]=UsbOutBuffer[i];
//          }
//          //usb_OUT_done();
//          usb_printf("ok\r\n");//发送数据 和 usb_OUT_done
//          break;
//         }
//      }
//    }
//    while(1){
//      if (bUsbOutReady){
//        if(OutNumber>0){
//          for(i=0;i<OutNumber;i++){
//            pageBuffer[i+64]=UsbOutBuffer[i];
//          }
//          //usb_OUT_done();
//          usb_printf("ok\r\n");//发送数据 和 usb_OUT_done
//          break;
//        }
//      }
//    }
//}


//void readBuffer256()
//{
//    u16 i;
//    while(1){
//      if (bUsbOutReady){
//        if(OutNumber>0){
//          for(i=0;i<OutNumber;i++){
//            pageBuffer[i]=UsbOutBuffer[i];
//          }
//          //usb_OUT_done();
//          usb_printf("ok\r\n");//发送数据 和 usb_OUT_done
//          break;
//        }
//      }
//    }
//    while(1){
//      if (bUsbOutReady){
//        if(OutNumber>0){
//          for(i=0;i<OutNumber;i++){
//            pageBuffer[i+64]=UsbOutBuffer[i];
//          }
//          //usb_OUT_done();
//          usb_printf("ok\r\n");//发送数据 和 usb_OUT_done
//          break;
//        }
//      }
//    }
//    while(1){
//      if (bUsbOutReady){
//        if(OutNumber>0){
//          for(i=0;i<OutNumber;i++){
//            pageBuffer[i+128]=UsbOutBuffer[i];
//          }
//          //usb_OUT_done();
//          usb_printf("ok\r\n");//发送数据 和 usb_OUT_done
//          break;
//        }
//      }
//    }
//    while(1){
//      if (bUsbOutReady){
//        if(OutNumber>0){
//          for(i=0;i<OutNumber;i++){
//            pageBuffer[i+192]=UsbOutBuffer[i];
//          }
//          //usb_OUT_done();
//          usb_printf("ok\r\n");//发送数据 和 usb_OUT_done
//          break;
//        }
//      }
//    }
//}


//执行命令缓存
void readCommand(void)
{
    uint8_t i;
    while(1)
    {
      if (bUsbOutReady)
      {
        if(OutNumber>0){
          for(i=0;i<OutNumber;i++){
            cmdBuffer[i]=UsbOutBuffer[i];
          }
          usb_OUT_done();
          return;
        }
      }
    }
}



// ---------------------------------------------------------

/*

GBA - TSOP56

WR      - WE
RD      - OE
CS      - CE
A0-A7   - D0-D7
A8-A15  - D8-D15
A16-A23 - A0-A7
CS2     - BYTE

*/


#define CS2 P13

void GBA_ROM_address_mode(void){
    // 推挽输出
    P6M0 = 0xff; P6M1 = 0x00;
    P7M0 = 0xff; P7M1 = 0x00;
    P0M0 = 0xff; P0M1 = 0x00;
}

void GBA_ROM_write_mode(void){
    // 推挽输出
    P6M0 = 0xff; P6M1 = 0x00;
    P7M0 = 0xff; P7M1 = 0x00;
    P0M0 = 0xff; P0M1 = 0x00;
}

void GBA_ROM_read_mode(void){
    // 高阻输入
    P6M0 = 0x00; P6M1 = 0xff;
    P7M0 = 0x00; P7M1 = 0xff;
    // 输出
    P0M0 = 0xff; P0M1 = 0x00;
}

void GBA_RAM_write_mode(void){
    // 推挽输出
    P6M0 = 0xff; P6M1 = 0x00;
    P7M0 = 0xff; P7M1 = 0x00;
    P0M0 = 0xff; P0M1 = 0x00;
}
void GBA_RAM_read_mode(void){
    // 推挽输出
    P6M0 = 0xff; P6M1 = 0x00;
    P7M0 = 0xff; P7M1 = 0x00;
    // 高阻输入
    P0M0 = 0x00; P0M1 = 0xff;
}
//---
void GBA_ROM_address(u32 addr){
    GBA_ROM_write_mode();
    P6 = addr & 0xff;
    P7 = (addr>>8) & 0xff;
    P0 = (addr>>16) & 0xff;
}
void GBA_ROM_read_data(){
    data16 = P7;
    data16 = (data16<<8) | P6;
    //return data16;
    // 数据写入 data16 不需要再返回
}
void GBA_ROM_write_data(u16 d16){
    P7 = (d16>>8) & 0xff;
    P6 = d16 & 0xff;
}
//---
// 读取数据
void GBA_ROM_read(u32 addr){
    GBA_ROM_address(addr);
    CE = 0;
    GBA_ROM_read_mode();
    OE = 0;
    _nop_();
    GBA_ROM_read_data();
    OE = 1;
    CE = 1;
    //return data16;
    // 数据在data16中 无需返回
}
// 写入数据
void GBA_ROM_write(u32 addr, u16 d16){
    GBA_ROM_address(addr);
    _nop_();
    CE = 0;
    GBA_ROM_write_data(d16);
    WE = 0;
    _nop_();
    WE = 1;
    GBA_ROM_read_mode();
    OE = 0;
    do{
        GBA_ROM_read_data();
    }while(data16 != d16);
    OE = 1;
    CE = 1;
}
// 写命令
void GBA_ROM_write_CMD(u32 addr, u16 d16){
    GBA_ROM_address(addr);
    CE = 0;
    GBA_ROM_write_data(d16);
    WE = 0;
    _nop_();
    WE = 1;
    OE = 1;
    CE = 1;
}


// ---------------------------------------------------------




void address_mode(void){
    // 推挽输出
    P0M0 = 0xff; P0M1 = 0x00;
    P6M0 = 0xff; P6M1 = 0x00;
    P7M0 = 0xff; P7M1 = 0x00;
}

void read_mode(void){
    // 高阻输入
    P6M0 = 0x00; P6M1 = 0xff;
    P7M0 = 0x00; P7M1 = 0xff;
}

void write_mode(void){
    // 推挽输出
    P6M0 = 0xff; P6M1 = 0x00;
    P7M0 = 0xff; P7M1 = 0x00;
}

//读数据
#define read_byte() P6
#define read_word() P7 << 8 | P6
#define read_word_L() P6
#define read_word_H() P7


//写数据
#define write_word(udat) \
    P7 = udat >> 8;      \
    P6 = udat;

#define write_word_cmd(udat) \
    P6 = udat; \
    P7 = udat>>8;

#define setAddress29(addr)  P4 = addr >> 16; \
                            P2 = addr >> 8;  \
                            P0 = addr; 
                            //P10 = addr >> 24; 
                            //P11 = addr >> 25;
                            
#define setAddress29_16(addr)   P2 = addr >> 8;  \
                                P0 = addr;                             
                          

#define setAddress_A24_A25(addr)  P10 = addr; P11 = addr >>1;


// 读取数据 每次64字节
void read29(){

#if 1
    j16 = 0;
    read_mode();

    WE = 1;
    OE = 1;
    CE = 0;
    buff16 = buff >> 1;
    address16 = address >> 1;

    for(i16=0; i16<buff16; i16++){
        
        setAddress29(address16 + i16);
        OE = 0;
        
        // 必须3个延迟 否则读取数据不准确
        _nop_();
        _nop_();
        _nop_();
        
        //data16 = read_word();
        wordL = read_word_L();
        wordH = read_word_H();
        OE = 1;
        
        if(md_mode==1){
            // MD先输出高 再输出低
            //pageBuffer[j16++] = (data16 >> 8) & 0xFF;
            //pageBuffer[j16++] = data16 & 0xFF;
            pageBuffer[j16++] = wordH;
            pageBuffer[j16++] = wordL;
        }else{
            // 非MD先低再高
            //pageBuffer[j16++] = data16 & 0xFF;
            //pageBuffer[j16++] = (data16 >> 8) & 0xFF;
            pageBuffer[j16++] = wordL;
            pageBuffer[j16++] = wordH;
        }
        
    }
    CE = 1;

#endif
    usb_send(pageBuffer,buff);
    
    address += buff;

}


// 查空
void checkFF(){
    checkFF_count = 0;
    address16 = address >> 1;
    read_mode();

    WE = 1;
    OE = 1;
    CE = 0;
    for(i16 = 0; i16 < buff16; i16++){
        setAddress29(address16 + i16);
        OE = 0;
        
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        
        data16 = read_word();
        OE = 1;
        if (data16 != 0xffff){
          CE = 1;
          checkFF_count++;
        }
    }
    OE = 1;
    CE = 1;
}



void write_word29(u32 addr, u16 dat) {
    write_word(dat);
    setAddress29(addr);
    _nop_();
    CE=0;
    WE=0;
    _nop_();//_nop_();
    WE=1;
    CE=1;
}

void write_word29_cmd(u32 addr, u16 dat) {
    write_word_cmd(dat);
    setAddress29_16(addr);
    _nop_();
    CE=0;
    WE=0;
    _nop_();//_nop_();
    WE=1;
    CE=1;
}


// 读取芯片ID 返回厂商
// 返回值放入 data16
u16 readCHip00(){
    
    u16 chip00 = 0;
    // 读取芯片厂家
    WE=1;
    OE=1;
    CE=1;
    write_mode();
    write_word29_cmd (0x555, 0xaa);
    write_word29_cmd (0x2aa, 0x55);
    write_word29_cmd (0x555, 0x90);
    
    _nop_();_nop_();_nop_();_nop_();
    
    // 读取芯片地址 0 
    read_mode();
    setAddress29(0);
    CE = 0;
    OE = 0;
    _nop_();_nop_();_nop_();_nop_();
    chip00 = read_word();
    CE = 1;
    OE = 1;
    
    // 退出芯片读取模式
    write_mode();
    write_word29_cmd (0x555, 0xaa);
    write_word29_cmd (0x2aa, 0x55);
    write_word29_cmd (0x555, 0xf0);
    
    return chip00;
}


// 读取CFI_BUFF
void readCfiBuff_1_5598(){
    WE = 1;
    CE = 1;
    OE = 1;
    write_mode();
    write_word29_cmd (0x55, 0x98);
    
    read_mode();
    // 读取芯片缓存长度
    setAddress29(0x2A);
    
    CE = 0;
    OE = 0;
    _nop_();_nop_();_nop_();_nop_();
    data16 = read_word();
    data8 = data16 & 0xff;
    CE = 1;
    OE = 1;
    
    // 退出芯片读取模式
    write_mode();
    write_word29_cmd (0x555, 0xaa);
    write_word29_cmd (0x2aa, 0x55);
    write_word29_cmd (0x555, 0xf0);
    
    // 设置CFI缓存
    if (data8 == 0 ){
        cfi_buff8 = 0;
        cfi_buff16 = 0;
    }else{
        cfi_buff8 = 1 << data8;
        cfi_buff16 = cfi_buff8 >> 1;
    }
    
}


// CFI写入后校验是否一致
// 1 正常 0 有错
u8 checkCfiData(u32 addr, u16 pageBuffer_index, u16 word_length){
    u16 i = 0;
    // 切换读取模式
    read_mode();
    CE = 0;
    
    // 连续写入buffer长度的数据
    for ( i = 0; i < word_length; i++) {
        setAddress29(addr + i);
        OE = 0;
        // 要写入的数据
        write16 = (pageBuffer[pageBuffer_index+(2*i+1)]);
        write16 = (write16<<8) | pageBuffer[pageBuffer_index+(2*i)];
        
        _nop_();_nop_();_nop_();_nop_();
        
        data16 = read_word();
        OE = 1;
        
        // 校验数据不一致 返回
        if (data16 != write16){
            CE = 1;
            return 0;
        }
        
    }
    
    CE = 1;
    
    return 1;
}

// CFI 写入
u8 writeCfiBuff(u32 addr, u16 pageBuffer_index, u16 byte_length){
    u16 i = 0;
    u16 word_length = byte_length >> 1;
    
    // 多这个判断优化不明显 反而降低速度
    // 写入数据是否全FF
//    u8 all_ff = 1;
//    for ( i=0; i<byte_length; i++){
//        if (pageBuffer[pageBuffer_index+i] != 0xff){
//          all_ff = 0;
//          break;
//        }
//    }
//    
//    // 全是 ff 跳过写入直接返回ok
//    if (all_ff == 1){
//        return 1;
//    }
    
    
    // 如果有需要写入的数据则继续执行代码

    // 切换回写入模式
    write_mode();
    // 批量写入命令
    write_word29_cmd (0x555, 0xaa);
    write_word29_cmd (0x2aa, 0x55);
    write_word29 (addr & 0xffff0000, 0x25);
    // setWord (addr, 0x25);
    // SA地址写入 word buffer 长度-1
    // addr 是实际地址 >> 1
    write_word29 (addr & 0xffff0000, word_length-1);
    // setWord (addr, word_length-1);

    // 连续写入buffer长度的数据
    for ( i = 0; i < word_length; i++) {
        // 要写入的数据
        write16 = (pageBuffer[pageBuffer_index+(2*i+1)]);
        write16 = (write16<<8) | pageBuffer[pageBuffer_index+(2*i)];
        // 写入缓存
        write_word29 (addr+i, write16);
    }

    // 提交
    write_word29 (addr & 0xffff0000, 0x29);
    // setWord (addr, 0x29);

    // 29GL256S 需要 160us 512字节需要 451us 超时 750us
    delay_us(50);

    // 切换读取模式
    read_mode();

    // 1us 延时计数器
    data32 = 0;

    // 设置最后一个地址
    //setAddress29(addr + word_length-1);
    // 校验写入成功。延迟时间大于 xx 之后跳出
//    OE = 0;
//    while(data32++ < 1000){
//        CE = 0;
//        delay_us(1);
//        data16 = read_word();
//        CE = 1;
//        if (data16 == write16){
//          OE = 1;
//          return 1;
//        }
//    }
//    OE = 1;

    // 通过 RY/BY 判断是否完成
    while (READY == 0){
        delay_us(1);
        if (data32++ >= 1000){
            return 0;
        }
    }
    
    // 
    if (READY == 1){
        data32 = 0;
        do {
            if(checkCfiData(addr, pageBuffer_index, word_length)==1){
                return 1;
            }
        } while(data32++ < 1000);
    }

    // 如果超时则返回0 表示异常
    return 0;
    
}


void write29(){
    u16 i;
    u8 errorBreak=0;//是否有错误
    u32 addr = address >> 1;
    WE=1;
    OE=1;
    CE=1;
    write_mode();
    
    // 读取写入数据到缓存
    //readBuffer();
    
    // 地址0判断是否有buffer快速写入
    if(address==0){
        data16 = readCHip00();
        data8 = data16 & 0xff;
        
        // 01 S29
        // 02 S29
        // 20 ST
        // C2 MX
        // EF Winbond
        if (data8==0x01 || data8==0x02 || data8==0x20 || data8==0xC2 || data8==0xEF){
            readCfiBuff_1_5598();
        }
    }
    
    
    // 如果有cfi缓存则使用高速写入
    if (cfi_buff8 > 0){
        
        // 写入
        write_word_index = 0;
        
        // 一直写到缓存用完
        while (buff16 > write_word_index){
            // 调用批量写入
            // 如果出错输出异常并结束
            if(writeCfiBuff(addr+write_word_index, write_word_index*2, cfi_buff8)==0){
          
                usb_printf("error: ");
//                usb_printf(" address: ");
//                usb_printf(addr+write_word_index+"");
//                usb_printf(", buffer: ");
//                usb_printf(cfi_buff8+"");
//                usb_printf("\r\n");

//                usb_printf(data16+"");
//                usb_printf("<>");
//                usb_printf(write16+"");
//                usb_printf("\r\n");

                return;
            }
            // 
            write_word_index += cfi_buff16;
        }
        
        
        CE=1;
        OE=1;
        WE=1;
                
        printf_usb("okn\r\n");
        
        // 更新地址
        address += buff;
        
    // 普通单字节写入模式
    }else{
        // 单字节写入
        for(i=0;i<(buff>>1);i++){
            write_mode();
            
            if(md_mode==0){
                temp16 = pageBuffer[(2*i)+1];
                temp16 = (temp16<<8) | pageBuffer[(2*i)];
            }else{
                // MD 先高再低
                temp16 = pageBuffer[(2*i)];
                temp16 = (temp16<<8) | pageBuffer[(2*i)+1];
            }

            write_word29_cmd (0x555, 0xaa);
            write_word29_cmd (0x2aa, 0x55);
            write_word29_cmd (0x555, 0xa0);
            write_word29((address>>1)+i,temp16);
            
            delay_us(1);
            
            read_mode();
            count16 = 0;
            
            OE = 0;
            do {
                CE = 0;
                delay_us(1);
                data16 = read_word();
                CE = 1;
            }while(data16 != temp16 && count16++ <= 500);
            OE = 1;
            
    //        OE = 0;
    //        CE = 0;
    //        // 读取数据到 data16
    //        data16 = read_word();
    //        while(data16 != temp16 && count16++ <= 500){
    //            delay_us(1);
    //            //delay_500();
    //            data16 = read_word();
    //        }
    //        OE = 1;
    //        CE = 1;
            
            if (count16>=480){
                break;
            }
        }
        
    

        CE=1;
        OE=1;
        WE=1;
        
        if(count16<460){
            //usb_printf("ok\r\n");
            
            printf_usb("ok1\r\n");
            //printf_usb(cfi_buff8);
        }else{
            usb_printf("error\r\n");
        }
        
        // 返回前更新地址
        address += buff;

    }
    
 
}



void erase29(){
    write_mode();
    RESET = 0;
    WE=1;
    CE=1;
    OE=1;
    delay_ms(1);
    RESET = 1;
    delay_ms(10);

    write_word29_cmd (0x555, 0xaa);
    write_word29_cmd (0x2aa, 0x55);
    write_word29_cmd (0x555, 0x80);
    write_word29_cmd (0x555, 0xaa);
    write_word29_cmd (0x2aa, 0x55);
    write_word29_cmd (0x555, 0x10);

    CE=1;
    delay_ms(100);
    usb_printf("ok\r\n");
}

void erase29_address(){
    write_mode();
    RESET = 0;
    WE=1;
    CE=1;
    OE=1;
    delay_ms(1);
    RESET = 1;
    delay_ms(10);

    write_word29_cmd (0x555, 0xaa);
    write_word29_cmd (0x2aa, 0x55);
    write_word29_cmd (0x555, 0x80);
    write_word29_cmd (0x555, 0xaa);
    write_word29_cmd (0x2aa, 0x55);
    P10 = address >> 24;
    P11 = address >> 25;
    write_word29 (address, 0x30);

    CE=1;
    delay_ms(100);
    P10 = 0;
    P11 = 0;
    usb_printf("ok\r\n");
}


void lock29(){
    WE=1;
    OE=1;
    CE=0;
    write_mode();
    write_word29_cmd (0x555, 0xaa);
    write_word29_cmd (0x2aa, 0x55);
    write_word29_cmd (0x555, 0xa0);
    CE=1;
    read_mode();
    usb_printf("ok\r\n");
}

void unlock29(){
    WE=1;
    OE=1;
    CE=0;
    write_mode();
    write_word29_cmd (0x555, 0xaa);
    write_word29_cmd (0x2aa, 0x55);
    write_word29_cmd (0x555, 0x80);
    write_word29_cmd (0x555, 0xaa);
    write_word29_cmd (0x2aa, 0x55);
    write_word29_cmd (0x555, 0x20);
    CE=1;
    WE=1;
    read_mode();
    usb_printf("ok\r\n");
}

void readChipID(){
    pageBuffer[0] = 0xff;
    pageBuffer[1] = 0xff;
    pageBuffer[2] = 0xff;
    pageBuffer[3] = 0xff;

    WE=1;
    OE=1;
    CE=1;
    write_mode();
    write_word29_cmd (0x555, 0xaa);
    write_word29_cmd (0x2aa, 0x55);
    write_word29_cmd (0x555, 0x90);

    // 读取芯片地址 0 和 1
    read_mode();
    setAddress29(0);
    CE = 0;
    OE = 0;
    _nop_();_nop_();
    data16 = read_word();
    CE = 1;
    OE = 1;
    pageBuffer[0] = data16 & 0xff;
    pageBuffer[1] = (data16 >> 8) & 0xff;

    setAddress29(1);
    CE = 0;
    OE = 0;
    _nop_();_nop_();
    data16 = read_word();
    CE = 1;
    OE = 1;
    pageBuffer[2] = data16 & 0xff;
    pageBuffer[3] = (data16 >> 8) & 0xff;

    write_mode();
    write_word29_cmd (0x555, 0xaa);
    write_word29_cmd (0x2aa, 0x55);
    write_word29_cmd (0x555, 0xf0);
    _nop_();_nop_();
    
    WE=1;
    OE=1;
    CE=1;
    // 输出4字节芯片ID
    usb_send(pageBuffer, 4);
}


void main()
{
    sys_init();                                     //管脚初始化
    usb_init();                                     //USB CDC 接口配置
    
    //IE2 |= 0x80;                                    //使能USB中断
    EA = 1;                                         //总中断控制打开
      
    read_mode();
    
    while (DeviceState != DEVSTATE_CONFIGURED);     //等待USB完成配置

    while (1) {
            
        readCommand();
            
        cmd    = cmdBuffer[0];
        
        switch(cmd){

            //case 'i':
            case 0x02:
                usb_printf("MD-STC\r\n");
                break;
            //case 'v':
            case 0x03:
                address = 0;
                // buff = 64;
                usb_printf(version);
                break;
            //case 't':
            case 0x04:
                usb_printf("ok\r\n");
                break;

            // 读取芯片ID
            case 0x05:
                readChipID();
                break;
            
            
            // GBA 读取rom
            case 0x20:
                
                CS2 = 1;
                GBA_ROM_address_mode();
                
                for(x=0;x<(buff>>1);x++){
                    GBA_ROM_read((address>>1)+x);
                    pageBuffer[(2*x)] = data16 & 0xff;
                    pageBuffer[(2*x)+1] = (data16>>8) & 0xff;
                }
                usb_send(pageBuffer,buff);
                address = address + buff;
                break;
                
            // 读取ID    
            case 0x21:
                
                CS2 = 1;
                GBA_ROM_address_mode();
                GBA_ROM_write_CMD(0x5555, 0xaa);
                GBA_ROM_write_CMD(0x2aaa, 0x55);
                GBA_ROM_write_CMD(0x5555, 0x90);
            
                GBA_ROM_read(0x0);
                pageBuffer[0] = data16 & 0xff;
                pageBuffer[1] = (data16 >> 8) & 0xff;
                GBA_ROM_read(0x1);
                pageBuffer[2] = data16 & 0xff;
                pageBuffer[3] = (data16 >> 8) & 0xff;
            
                // 退出
                GBA_ROM_write_CMD(0x5555, 0xaa);
                GBA_ROM_write_CMD(0x2aaa, 0x55);
                GBA_ROM_write_CMD(0x5555, 0xf0);
            
                usb_send(pageBuffer, 4);
                break;

            // 擦除
            case 0x22:

                CS2 = 1;
                GBA_ROM_address_mode();

                GBA_ROM_write_CMD (0x5555, 0xaa);
                GBA_ROM_write_CMD (0x2aaa, 0x55);
                GBA_ROM_write_CMD (0x5555, 0x80);
                GBA_ROM_write_CMD (0x5555, 0xaa);
                GBA_ROM_write_CMD (0x2aaa, 0x55);
                GBA_ROM_write_CMD (0x5555, 0x10);

                usb_printf("ok\n\r");
                break;
                            
            //case 'r':
            case 0xA1:
                read29();
                break;
            
            
            // 检查数据是否全是FF
            case 0xA2:
                checkFF();
                pageBuffer[0] = checkFF_count>0?1:0;
                usb_send(pageBuffer, 1);
                break;

            //case 'w':
            case 0xB1:
                write29();
                break;
                
            // 写入缓存 最大4k
            case 0xB2:
                //readBuffer();
                buffer_index = (cmdBuffer[1] << 8) | cmdBuffer[2];
                for (x = 0; x < 32; x++) {
                    pageBuffer[buffer_index + x] = cmdBuffer[3 + x];
                }
                //usb_printf("ok\r\n");
                printf_usb("ok\r\n");
                break;
                
            // 擦除
            //case 'e':
            case 0xC1:
                erase29();
                delay_ms(250);
                break;
            
            // 块擦除地址
            case 0xC2:
                address = cmdBuffer[1];
                address = (address<<8) | cmdBuffer[2];
                address = (address<<8) | cmdBuffer[3];
                address = (address<<8) | cmdBuffer[4];
                
                erase29_address();
                delay_ms(250);
                break;
                
            //case 'l':
            case 0xD1:
                lock29();
                break;

            //case 'u':
            case 0xD2:
                unlock29();
                break;

            
            // 设置地址高位 A24 A25
            case 0xE0:
                data8 = cmdBuffer[1];
                setAddress_A24_A25(data8);
                usb_printf("ok\r\n");
                break;
            
            // 地址 address
            case 0xE1:
                //address = cmdBuffer[1]<<24 + cmdBuffer[2]<<16 + cmdBuffer[3]<<8 + cmdBuffer[4];
                address = cmdBuffer[1];
                address = (address<<8) | cmdBuffer[2];
                address = (address<<8) | cmdBuffer[3];
                address = (address<<8) | cmdBuffer[4];
                
                if(address == 0){                    
                    // 地址线高位2个地址
                    P10 = 0;
                    P11 = 0;
                }
                
                usb_printf("ok\r\n");
                break;
            // 设置缓存长度
            case 0xE2:
                
                buff = cmdBuffer[1];
                buff = (buff<<8) | cmdBuffer[2];
                buff = (buff<<8) | cmdBuffer[3];
                buff = (buff<<8) | cmdBuffer[4];
            
                buff16 = buff >> 1;
            
                //buff = cmdBuffer[4];
                usb_printf("ok\r\n");
                break;
            // 设置写入缓存长度 1 128 256 512 1是单字节写入 其他是page写入
            case 0xE3:
            
                writeBuff = cmdBuffer[3];
                writeBuff = (writeBuff<<8) | cmdBuffer[4];
                usb_printf("ok\r\n");
                break;
            
            // 设置读写方式，MD默认1 高位+低位。8位模式 低位+高位
            case 0xE4:
                md_mode = cmdBuffer[4]==0?0:(cmdBuffer[4] & 0xff);
            
                if(md_mode==0 || md_mode==1){
                    address_mode();
                }
            
                usb_printf("ok\r\n");
                break;
            
            
            
            // 测试用 返回缓存数据
            case 0xE9:
                readBuffer();
                for(data8=0;data8<64;data8++){
                    usb_sendchar(pageBuffer[data8]);
                }
                break;
                
                
                

            case 0xF1:
                usb_send((address<0xf1?"a":"b"),1);
                usb_printf("\r\n");
                break;
            case 0xF2:
                usb_send((buff==128?"a":"b"),1);
                usb_printf("\r\n");
                break;
            case 0xF3:
                usb_send(writeBuff==1?"x":"y",1);
                usb_printf("\r\n");
                break;
            
            case 0xF4:
                data16 = 0;
                data16 = readCHip00();
                data8 = data16 & 0xff;
                pageBuffer[0] = data8;
                
                usb_send(pageBuffer,1);
            
                //usb_printf("%ld",data16);
                //printf_usb("%x",data8);
                //printf_usb("%x",0xff);
                //printf_usb("%x",data16);
                break;
            
            case 0xF6:
                readCfiBuff_1_5598();
                //usb_printf(cfi_buff8+"");
                //usb_printf("\r\n");
                //printf_usb("%x",cfi_buff8);
                
                //pageBuffer[0] = cfi_buff8;
                
                //pageBuffer[0] = data16 & 0xff;
                //pageBuffer[1] = data16 >> 8 & 0xff;
                //usb_send(pageBuffer,2);
                
                
                pageBuffer[0] = cfi_buff8 & 0xff;
                pageBuffer[1] = cfi_buff8 >> 8;
                usb_send(pageBuffer,2);
            
                break;
            
                
            default:    break;

        }
        
        WE = 1;
        OE = 1;
        CE = 1;
        
        setAddress29(0);
    }
}


